libxl: Fix migration of HVM guests
authorIan Campbell <ian.campbell@citrix.com>
Thu, 28 Oct 2010 11:19:43 +0000 (12:19 +0100)
committerIan Campbell <ian.campbell@citrix.com>
Thu, 28 Oct 2010 11:19:43 +0000 (12:19 +0100)
In the default "QemuDeviceModelRecord"-style HVM tail of the migration
protocol the size of the qemu save record is unknown at the receiver
and therefore it must read until EOF. This is not compatible with the
xl migration protocol which contains a post-migration handshake and
therefore cannot close the socket on the sending end.

What is required is an explicit length field for the save record,
which the "RemusDeviceModelState"-style HVM tail includes.

Rather than overload the "RemusDeviceModelState" name for a non-Remus
use case (on off chance that they need to diverge for some reason in
the future) introduce a third style called "DeviceModelRecord0002"
which is identical to current "RemusDeviceModelState"-style.

Hopefully the inclusion of a number here will allow easier extension
in the future without needing to come up with increasingly less
helpful names!

Also propagate errors from xc_domain_save and
libxl__domain_suspend_common to callers.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
tools/libxc/xc_domain_restore.c
tools/libxc/xg_save_restore.h
tools/libxl/libxl.c
tools/libxl/libxl_dom.c
tools/libxl/libxl_internal.h

index c9f3916b34ec77b2d97d6f3df34fd85c38b99b86..7c64a4929bd07fe8f7f0d90666d1e5fe0fe76dae 100644 (file)
@@ -494,13 +494,18 @@ static int buffer_tail_hvm(xc_interface *xch, struct restore_ctx *ctx,
         return -1;
     }
 
-    /* The normal live-migration QEMU record has no length information.
+    /* The legacy live-migration QEMU record has no length information.
      * Short of reimplementing the QEMU parser, we're forced to just read
-     * until EOF. Remus gets around this by sending a different signature
-     * which includes a length prefix */
+     * until EOF.
+     *
+     * Gets around this by sending a different signatures for the new
+     * live-migration QEMU record and Remus which includes a length
+     * prefix
+     */
     if ( !memcmp(qemusig, "QemuDeviceModelRecord", sizeof(qemusig)) )
         return compat_buffer_qemu(xch, ctx, fd, buf);
-    else if ( !memcmp(qemusig, "RemusDeviceModelState", sizeof(qemusig)) )
+    else if ( !memcmp(qemusig, "DeviceModelRecord0002", sizeof(qemusig)) ||
+              !memcmp(qemusig, "RemusDeviceModelState", sizeof(qemusig)) )
         return buffer_qemu(xch, ctx, fd, buf);
 
     qemusig[20] = '\0';
index 2c82ce74048472a1c71e26cd0469b1c3c43290fc..b13bdef649dde1cd52b4e36c110f46e3d64dd907 100644 (file)
  *  Qemu context:
  *     char[21]         : Signature:
  *       "QemuDeviceModelRecord" : Read Qemu save data until EOF
- *       "RemusDeviceModelState" : uint32_t length field followed by that many
+ *       "DeviceModelRecord0002" : uint32_t length field followed by that many
  *                                 bytes of Qemu save data
+ *       "RemusDeviceModelState" : Currently the same as "DeviceModelRecord0002".
  *
  * PV TAIL:
  *
index f40d41b7fca7f92146faf86aff7f183c3245349a..79d9f0d3191af3f37ea64aabbcfbc1a5daccecee 100644 (file)
@@ -686,8 +686,8 @@ int libxl_domain_suspend(libxl_ctx *ctx, libxl_domain_suspend_info *info,
     int debug = info != NULL && info->flags & XL_SUSPEND_DEBUG;
     int rc = 0;
 
-    libxl__domain_suspend_common(ctx, domid, fd, hvm, live, debug);
-    if (hvm)
+    rc = libxl__domain_suspend_common(ctx, domid, fd, hvm, live, debug);
+    if (!rc && hvm)
         rc = libxl__domain_save_device_model(ctx, domid, fd);
     return rc;
 }
index 5352f65ef63045618786a092fbf33dfcafb91272..bbba8057e8f98aacb04f974605544081fa029945 100644 (file)
@@ -442,14 +442,17 @@ int libxl__domain_suspend_common(libxl_ctx *ctx, uint32_t domid, int fd,
     callbacks.switch_qemu_logdirty = libxl__domain_suspend_common_switch_qemu_logdirty;
     callbacks.data = &si;
 
-    xc_domain_save(ctx->xch, fd, domid, 0, 0, flags, &callbacks, hvm);
+    rc = xc_domain_save(ctx->xch, fd, domid, 0, 0, flags, &callbacks, hvm);
+    if ( rc ) {
+        LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "saving domain");
+        rc = ERROR_FAIL;
+    }
 
     if (si.suspend_eventchn > 0)
         xc_suspend_evtchn_release(ctx->xch, si.xce, domid, si.suspend_eventchn);
     if (si.xce > 0)
         xc_evtchn_close(si.xce);
 
-    rc = 0;
 out:
     libxl__free_all(&gc);
     return rc;
@@ -461,15 +464,32 @@ int libxl__domain_save_device_model(libxl_ctx *ctx, uint32_t domid, int fd)
     int fd2, c;
     char buf[1024];
     char *filename = libxl__sprintf(&gc, "/var/lib/xen/qemu-save.%d", domid);
+    struct stat st;
+    uint32_t qemu_state_len;
 
     LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Saving device model state to %s", filename);
     libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/0/device-model/%d/command", domid), "save");
     libxl__wait_for_device_model(ctx, domid, "paused", NULL, NULL);
 
+    if (stat(filename, &st) < 0)
+    {
+        LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Unable to stat qemu save file\n");
+        return ERROR_FAIL;
+    }
+
+    qemu_state_len = st.st_size;
+    LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Qemu state is %d bytes\n", qemu_state_len);
+
     c = libxl_write_exactly(ctx, fd, QEMU_SIGNATURE, strlen(QEMU_SIGNATURE),
                             "saved-state file", "qemu signature");
     if (c)
         return c;
+
+    c = libxl_write_exactly(ctx, fd, &qemu_state_len, sizeof(qemu_state_len),
+                            "saved-state file", "saved-state length");
+    if (c)
+        return c;
+
     fd2 = open(filename, O_RDONLY);
     while ((c = read(fd2, buf, sizeof(buf))) != 0) {
         if (c < 0) {
index e89ac2fe9ff1ab373416a49f1b601f6d8444ba5c..e3fc22dd9f0b2c73448938b48fa16ba161b043f9 100644 (file)
@@ -44,7 +44,7 @@
 #define LIBXL_PV_EXTRA_MEMORY 1024
 #define LIBXL_HVM_EXTRA_MEMORY 2048
 #define LIBXL_MIN_DOM0_MEM (128*1024)
-#define QEMU_SIGNATURE "QemuDeviceModelRecord"
+#define QEMU_SIGNATURE "DeviceModelRecord0002"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))